{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 说明\n",
    "\n",
    "请按照填空顺序编号分别完成 参数优化，不同基函数的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def load_data(filename):\n",
    "    \"\"\"载入数据。\"\"\"\n",
    "    xys = []\n",
    "    with open(filename, 'r') as f:\n",
    "        for line in f:\n",
    "            xys.append(map(float, line.strip().split()))\n",
    "        xs, ys = zip(*xys)\n",
    "        return np.asarray(xs), np.asarray(ys)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.1  0.2  0.45 0.6  0.85 0.95 1.15 1.2  1.3  1.45]\n",
      "[0.3995  0.79601 1.7549  2.29393 3.10384 3.39025 3.88829 3.99612 4.19067\n",
      " 4.42814]\n"
     ]
    }
   ],
   "source": [
    "# 测试\n",
    "x, y = load_data(\"./test.txt\")\n",
    "xa = np.array(x)\n",
    "ya = np.array(y)\n",
    "print(xa[:10])\n",
    "print(ya[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 不同的基函数 (basis function)的实现 填空顺序 2\n",
    "\n",
    "请分别在这里实现“多项式基函数”以及“高斯基函数”\n",
    "\n",
    "其中以及训练集的x的范围在0-25之间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def identity_basis(x):\n",
    "    # 函数解释 https://numpy.org/doc/stable/reference/generated/numpy.expand_dims.html\n",
    "    # 即给目标矩阵 x 添加新维度 \n",
    "    ret = np.expand_dims(x, axis=1)\n",
    "    return ret\n",
    "\n",
    "def multinomial_basis(x, feature_num=10):\n",
    "    '''多项式基函数'''\n",
    "    x = np.expand_dims(x, axis=1) # shape(N, 1)\n",
    "    #==========\n",
    "    #todo '''请实现多项式基函数'''\n",
    "    #==========\n",
    "    ret = None\n",
    "    return ret\n",
    "\n",
    "def gaussian_basis(x, feature_num=10):\n",
    "    '''高斯基函数'''\n",
    "    #==========\n",
    "    #todo '''请实现高斯基函数'''\n",
    "    #==========\n",
    "    ret = None\n",
    "    return ret"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 返回一个训练好的模型 填空顺序 1 用最小二乘法进行模型优化 \n",
    "## 填空顺序 3 用梯度下降进行模型优化\n",
    "> 先完成最小二乘法的优化 (参考书中第二章 2.3中的公式)\n",
    "\n",
    "> 再完成梯度下降的优化   (参考书中第二章 2.3中的公式)\n",
    "\n",
    "在main中利用训练集训练好模型的参数，并且返回一个训练好的模型。\n",
    "\n",
    "计算出一个优化后的w，请分别使用最小二乘法以及梯度下降两种办法优化w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X shape:  (2, 200)\n",
      "y shape: (200,)\n",
      "w1: [0.93433662 0.87644906]\n",
      "w2 (2, 200)\n",
      "f1(x): [0.96988272 1.06331638 1.29690054 1.43705103 1.67063519 1.76406885\n",
      " 1.95093617 1.997653   2.09108666 2.23123716]\n",
      " x:  [0.1  0.2  0.45 0.6  0.85 0.95 1.15 1.2  1.3  1.45]\n",
      " y:  [0.3995  0.79601 1.7549  2.29393 3.10384 3.39025 3.88829 3.99612 4.19067\n",
      " 4.42814]\n"
     ]
    }
   ],
   "source": [
    "def main(x_train, y_train):\n",
    "    \"\"\"\n",
    "    训练模型，并返回从x到y的映射。\n",
    "    \"\"\"\n",
    "    basis_func = identity_basis\n",
    "    # ones_like 提供一个和 目标矩阵同纬度的矩阵，用 1 填充\n",
    "    phi0 = np.expand_dims(np.ones_like(x_train), axis=1)\n",
    "    phi1 = basis_func(x_train)\n",
    "    # concatenate 按照目标维度进行数组拼接\n",
    "    phi = np.concatenate([phi1, phi0], axis=1)\n",
    "    \n",
    "    \n",
    "    #==========\n",
    "    #todo '''计算出一个优化后的w，请分别使用最小二乘法以及梯度下降两种办法优化w'''\n",
    "    #==========\n",
    "    \n",
    "    # 最小二乘法\n",
    "    X = phi.T\n",
    "    print(\"X shape: \",X.shape)\n",
    "\n",
    "    print(\"y shape:\",ya.shape)\n",
    "    \n",
    "    w1 = np.linalg.inv(np.dot(X,X.T)).dot(X).dot(ya)\n",
    "    print(\"w1:\",w1)\n",
    "    \n",
    "    # 梯度下降\n",
    "    eta = 0.1  # learning rate / 步长\n",
    "    n_iterations = 1 # 迭代次数\n",
    "\n",
    "    w2 = np.random.randn(2,1)  # 随机化参数\n",
    "    X = X.T\n",
    "    for iteration in range(n_iterations):    \n",
    "        gradients = 2/ya.size * X.T.dot(X.dot(w2) - ya)    \n",
    "        w2 = w2 - eta * gradients\n",
    "    print(\"w2\",w2.shape)\n",
    "    # print(\"w2:\",w2)\n",
    "\n",
    "    def f1(x):\n",
    "        phi0 = np.expand_dims(np.ones_like(x), axis=1)\n",
    "        phi1 = basis_func(x)\n",
    "        phi = np.concatenate([phi1, phi0], axis=1)\n",
    "        y = np.dot(phi, w1)\n",
    "        return y\n",
    "    return f1\n",
    "F1 = main(xa,ya)\n",
    "yp1 = F1(xa)\n",
    "print(\"f1(x):\",yp1[:10])\n",
    "print(\" x: \",xa[:10])\n",
    "print(\" y: \",ya[:10])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 测试准确度\n",
    "import matplotlib.pyplot as plt\n",
    "plt.title('least square method')\n",
    "plt.scatter(xa, ya, color = \"blue\",label = \"predicated data\")\n",
    "plt.scatter(xa, yp1, color = \"red\", label = \"predtraining data\")\n",
    "\n",
    "plt.legend(loc='best')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 评估结果 \n",
    "> 没有需要填写的代码，但是建议读懂"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate(ys, ys_pred):\n",
    "    \"\"\"评估模型。\"\"\"\n",
    "    std = np.sqrt(np.mean(np.abs(ys - ys_pred) ** 2))\n",
    "    return std\n",
    "\n",
    "# 程序主入口（建议不要改动以下函数的接口）\n",
    "if __name__ == '__main__':\n",
    "    train_file = 'train.txt'\n",
    "    test_file = 'test.txt'\n",
    "    # 载入数据\n",
    "    x_train, y_train = load_data(train_file)\n",
    "    x_test, y_test = load_data(test_file)\n",
    "    print(x_train.shape)\n",
    "    print(x_test.shape)\n",
    "\n",
    "    # 使用线性回归训练模型，返回一个函数f()使得y = f(x)\n",
    "    f = main(x_train, y_train)\n",
    "\n",
    "    y_train_pred = f(x_train)\n",
    "    std = evaluate(y_train, y_train_pred)\n",
    "    print('训练集预测值与真实值的标准差：{:.1f}'.format(std))\n",
    "    \n",
    "    # 计算预测的输出值\n",
    "    y_test_pred = f(x_test)\n",
    "    # 使用测试集评估模型\n",
    "    std = evaluate(y_test, y_test_pred)\n",
    "    print('预测值与真实值的标准差：{:.1f}'.format(std))\n",
    "\n",
    "    #显示结果\n",
    "    plt.plot(x_train, y_train, 'ro', markersize=3)\n",
    "#     plt.plot(x_test, y_test, 'k')\n",
    "    plt.plot(x_test, y_test_pred, 'k')\n",
    "    plt.xlabel('x')\n",
    "    plt.ylabel('y')\n",
    "    plt.title('Linear Regression')\n",
    "    plt.legend(['train', 'test', 'pred'])\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "metadata": {
     "collapsed": false
    },
    "source": []
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
